{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- https://course.rs/basic/crate-module/intro.html\n",
    "\n",
    "跟其它语言一样，Rust 也提供了相应概念用于代码的组织管理：\n",
    "\n",
    "- 项目(Packages)：一个 `Cargo` 提供的 `feature`，可以用来构建、测试和分享包\n",
    "- 包(Crate)：一个由多个模块组成的树形结构，可以作为三方库进行分发，也可以生成可执行文件进行运行\n",
    "- 模块(Module)：可以一个文件多个模块，也可以一个文件一个模块，模块可以被认为是真实项目中的代码组织单元"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 包和项目 / Crate and Package\n",
    "\n",
    "- https://course.rs/basic/crate-module/crate.html\n",
    "- https://practice-zh.course.rs/crate-module/crate.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/crate-module/crate.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 包 Crate"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "对于 Rust 而言，包是一个独立的可编译单元，它编译后会生成一个可执行文件或者一个库。\n",
    "\n",
    "一个包会将相关联的功能打包在一起，使得该功能可以很方便的在多个项目中分享。例如标准库中没有提供但是在三方库中提供的 `rand` 包，它提供了随机数生成的功能，我们只需要将该包通过 `use rand;` 引入到当前项目的作用域中，就可以在项目中使用 `rand` 的功能：`rand::XXX`。\n",
    "\n",
    "同一个包中不能有同名的类型，但是在不同包中就可以。例如，虽然 `rand` 包中，有一个 `Rng` 特征，可是我们依然可以在自己的项目中定义一个 `Rng`，前者通过 `rand::Rng` 访问，后者通过 `Rng` 访问，对于编译器而言，这两者的边界非常清晰，不会存在引用歧义。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 项目 Package"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "鉴于 Rust 团队标新立异的起名传统，以及包的名称被 `crate` 占用，库的名称被 `library` 占用，经过斟酌， 我们决定将 `Package` 翻译成项目，你也可以理解为工程、软件包。\n",
    "\n",
    "由于 `Package` 就是一个项目，因此它包含有独立的 `Cargo.toml` 文件，以及因为功能性被组织在一起的一个或多个包。一个 `Package` 只能包含**一个**库(library)类型的包，但是可以包含**多个**二进制可执行类型的包。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 二进制 Package"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "让我们来创建一个二进制 `Package`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "    Creating binary (application) `my-project` package\n",
       "note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cargo new my-project"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       ".\n",
       "├── Cargo.toml\n",
       "└── src\n",
       "    └── main.rs\n",
       "\n",
       "1 directory, 2 files\n"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd my-project && tree"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "Hello, world!\n"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd my-project && cargo run -q"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里，Cargo 为我们创建了一个名称是 `my-project` 的 `Package`，同时在其中创建了 `Cargo.toml` 文件，可以看一下该文件，里面并没有提到 `src/main.rs` 作为程序的入口，原因是 Cargo 有一个惯例：**`src/main.rs` 是二进制包的根文件，该二进制包的包名跟所属 `Package` 相同，在这里都是 `my-project`**，所有的代码执行都从该文件中的 `fn main()` 函数开始。\n",
    "\n",
    "使用 `cargo run` 可以运行该项目，输出：`Hello, world!`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 库 Package"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "再来创建一个库类型的 `Package`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "    Creating library `my-lib` package\n",
       "note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cargo new my-lib --lib"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       ".\n",
       "├── Cargo.toml\n",
       "└── src\n",
       "    └── lib.rs\n",
       "\n",
       "1 directory, 2 files\n"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd my-lib && tree"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "Shell command failed with exit code 101: error: a bin target must be available for `cargo run`\n",
     "output_type": "error",
     "traceback": [
      "Shell command failed with exit code 101: error: a bin target must be available for `cargo run`\n"
     ]
    }
   ],
   "source": [
    "! cd my-lib && cargo run"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "原因是库类型的 `Package` 只能作为三方库被其它项目引用，而不能独立运行，只有之前的二进制 `Package` 才可以运行。\n",
    "\n",
    "与 `src/main.rs` 一样，Cargo 知道，如果一个 `Package` 包含有 `src/lib.rs`，意味它包含有一个库类型的同名包 `my-lib`，该包的根文件是 `src/lib.rs`。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 易混淆的 Package 和包"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "看完上面，相信大家看出来为何 `Package` 和包容易被混淆了吧？因为你用 `cargo new` 创建的 `Package` 和它其中包含的包是同名的！\n",
    "\n",
    "不过，只要你牢记 `Package` 是一个项目工程，而包只是一个编译单元，也就不会再混淆这两个概念：`src/main.rs` 和 `src/lib.rs` 都是编译单元，因此它们都是包。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 典型的 Package 结构"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "上面创建的 `Package` 中仅包含 `src/main.rs` 文件，意味着它仅包含一个二进制同名包 `my-project`。如果一个 `Package` 同时拥有 `src/main.rs` 和 `src/lib.rs`，那就意味着它包含两个包：库包和二进制包，这两个包名也都是 `my-project` —— 都与 `Package` 同名。\n",
    "\n",
    "一个真实项目中典型的 `Package`，会包含多个二进制包，这些包文件被放在 `src/bin` 目录下，每一个文件都是独立的二进制包，同时也会包含一个库包，该包只能存在一个 `src/lib.rs`：\n",
    "\n",
    "```shell\n",
    ".\n",
    "├── Cargo.toml\n",
    "├── Cargo.lock\n",
    "├── src\n",
    "│   ├── main.rs\n",
    "│   ├── lib.rs\n",
    "│   └── bin\n",
    "│       └── main1.rs\n",
    "│       └── main2.rs\n",
    "├── tests\n",
    "│   └── some_integration_tests.rs\n",
    "├── benches\n",
    "│   └── simple_bench.rs\n",
    "└── examples\n",
    "    └── simple_example.rs\n",
    "```\n",
    "\n",
    "- 唯一库包：`src/lib.rs`\n",
    "- 默认二进制包：`src/main.rs`，编译后生成的可执行文件与 `Package` 同名\n",
    "- 其余二进制包：`src/bin/main1.rs` 和 `src/bin/main2.rs`，它们会分别生成一个文件同名的二进制可执行文件\n",
    "- 集成测试文件：`tests` 目录下\n",
    "- 基准性能测试 `benchmark` 文件：`benches` 目录下\n",
    "- 项目示例：`examples` 目录下\n",
    "\n",
    "这种目录结构基本上是 Rust 的标准目录结构，在 `GitHub` 的大多数项目上，你都将看到它的身影。\n",
    "\n",
    "理解了包的概念，我们再来看看构成包的基本单元：模块。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 模块 Module\n",
    "\n",
    "- https://course.rs/basic/crate-module/module.html\n",
    "- https://practice-zh.course.rs/crate-module/crate.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/crate-module/crate.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 创建嵌套模块"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "    Creating library `restaurant` package\n",
       "note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cargo new --lib restaurant "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "// 餐厅前厅，用于吃饭\n",
       "mod front_of_house {\n",
       "    mod hosting {\n",
       "        fn add_to_waitlist() {}\n",
       "\n",
       "        fn seat_at_table() {}\n",
       "    }\n",
       "\n",
       "    mod serving {\n",
       "        fn take_order() {}\n",
       "\n",
       "        fn serve_order() {}\n",
       "\n",
       "        fn take_payment() {}\n",
       "    }\n",
       "}\n"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd restaurant && cat src/lib.rs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "以上的代码创建了三个模块，有几点需要注意的：\n",
    "\n",
    "- 使用 `mod` 关键字来创建新模块，后面紧跟着模块名称\n",
    "- 模块可以嵌套，这里嵌套的原因是招待客人和服务都发生在前厅，因此我们的代码模拟了真实场景\n",
    "- 模块中可以定义各种 Rust 类型，例如函数、结构体、枚举、特征等\n",
    "- 所有模块均定义在同一个文件中\n",
    "\n",
    "类似上述代码中所做的，使用模块，我们就能将功能相关的代码组织到一起，然后通过一个模块名称来说明这些代码为何被组织在一起。这样其它程序员在使用你的模块时，就可以更快地理解和上手。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 模块树"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在[上一节](https://course.rs/basic/crate-module/crate.html)中，我们提到过 `src/main.rs` 和 `src/lib.rs` 被称为包根(crate root)，这个奇葩名称的来源（我不想承认是自己翻译水平太烂-,-）是由于这两个文件的内容形成了一个模块 `crate`，该模块位于包的树形结构（由模块组成的树形结构）的根部：\n",
    "\n",
    "```shell\n",
    "crate\n",
    " └── front_of_house\n",
    "     ├── hosting\n",
    "     │   ├── add_to_waitlist\n",
    "     │   └── seat_at_table\n",
    "     └── serving\n",
    "         ├── take_order\n",
    "         ├── serve_order\n",
    "         └── take_payment\n",
    "```\n",
    "\n",
    "这颗树展示了模块之间**彼此的嵌套**关系，因此被称为**模块树**。其中 `crate` 包根是 `src/lib.rs` 文件，包根文件中的三个模块分别形成了模块树的剩余部分。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**父子模块**\n",
    "\n",
    "如果模块 `A` 包含模块 `B`，那么 `A` 是 `B` 的父模块，`B` 是 `A` 的子模块。在上例中，`front_of_house` 是 `hosting` 和 `serving` 的父模块，反之，后两者是前者的子模块。\n",
    "\n",
    "聪明的读者，应该能联想到，模块树跟计算机上文件系统目录树的相似之处。不仅仅是组织结构上的相似，就连使用方式都很相似：每个文件都有自己的路径，用户可以通过这些路径使用它们，在 Rust 中，我们也通过路径的方式来引用模块。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 用路径引用模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "想要调用一个函数，就需要知道它的路径，在 Rust 中，这种路径有两种形式：\n",
    "\n",
    "- **绝对路径**，从包根开始，路径名以包名或者 `crate` 作为开头\n",
    "- **相对路径**，从当前模块开始，以 `self`，`super` 或当前模块的标识符作为开头\n",
    "\n",
    "让我们继续经营那个惨淡的小餐馆，这次为它实现一个小功能： 文件名：src/lib.rs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "mod front_of_house {\n",
       "    mod hosting {\n",
       "        fn add_to_waitlist() {}\n",
       "    }\n",
       "}\n",
       "\n",
       "pub fn eat_at_restaurant() {\n",
       "    // 绝对路径\n",
       "    crate::front_of_house::hosting::add_to_waitlist();\n",
       "\n",
       "    // 相对路径\n",
       "    front_of_house::hosting::add_to_waitlist();\n",
       "}\n"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd restaurant && cat src/lib.rs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**相对路径引用**\n",
    "\n",
    "再回到模块树中，因为 `eat_at_restaurant` 和 `front_of_house` 都处于包根 `crate` 中，因此相对路径可以使用 `front_of_house` 作为开头：\n",
    "\n",
    "```rust\n",
    "front_of_house::hosting::add_to_waitlist();\n",
    "```\n",
    "\n",
    "如果类比文件系统，那么它类似于调用同一个目录下的程序，你可以这么做：`front_of_house/hosting/add_to_waitlist`，嗯也很符合直觉。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**绝对还是相对？**\n",
    "- 如果调用处和定义处通常分离、且你预期定义的位置更稳定，**可以优先用绝对路径**。\n",
    "- 如果两个模块会一起搬迁、相对布局较稳定，**相对路径更省心**。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**绝对路径**（从 `crate::` 开始）和 **相对路径**（从当前模块或 `self::`/`super::` 开始）都能引用同一对象。\n",
    "\n",
    "关键考虑是：当代码（模块或函数）被移动位置时，哪种写法能 **最少改动路径**。\n",
    "\n",
    "若你把 `front_of_house` 与 `eat_at_restaurant` 一起移入 `customer_experience` 模块：\n",
    "\n",
    "- 绝对路径必须改成 `crate::customer_experience::front_of_house::...`\n",
    "- 相对路径保持不变，因为两者之间的相对关系没变。\n",
    "\n",
    "若只移动 `eat_at_restaurant` 到 `dining` 模块：\n",
    "\n",
    "- 相对路径要改（因同级关系改变）。\n",
    "- 绝对路径仍是 `crate::front_of_house::...`，无需修改。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 代码可见性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "module `hosting` is private",
     "output_type": "error",
     "traceback": [
      "    crate::front_of_house::hosting::add_to_waitlist();",
      "\u001b[91m                           ^^^^^^^\u001b[0m \u001b[94mprivate module\u001b[0m",
      "    crate::front_of_house::hosting::add_to_waitlist();",
      "\u001b[91m                                    ^^^^^^^^^^^^^^^\u001b[0m \u001b[94mfunction `add_to_waitlist` is not publicly re-exported\u001b[0m",
      "module `hosting` is private"
     ]
    }
   ],
   "source": [
    "mod front_of_house {\n",
    "    mod hosting {\n",
    "        fn add_to_waitlist() {}\n",
    "    }\n",
    "}\n",
    "\n",
    "pub fn eat_at_restaurant() {\n",
    "    // 绝对路径\n",
    "    crate::front_of_house::hosting::add_to_waitlist();\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "    Creating library `code_visibility` package\n",
       "note: see more `Cargo.toml` keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cargo new --lib code_visibility"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "Shell command failed with exit code 101:    Compiling code_visibility v0.1.0 (/mnt/d/dev_learn/learnrustbyai_fk/rust_course/02_intro/2.12_包和模块/code_visibility)\nerror[E0603]: module `hosting` is private\n --> src/lib.rs:9:21\n  |\n9 |     front_of_house::hosting::add_to_waitlist();\n  |                     ^^^^^^^  --------------- function `add_to_waitlist` is not publicly re-exported\n  |                     |\n  |                     private module\n  |\nnote: the module `hosting` is defined here\n --> src/lib.rs:2:5\n  |\n2 |     mod hosting {\n  |     ^^^^^^^^^^^\n\nFor more information about this error, try `rustc --explain E0603`.\nerror: could not compile `code_visibility` (lib) due to 1 previous error\n",
     "output_type": "error",
     "traceback": [
      "Shell command failed with exit code 101:    Compiling code_visibility v0.1.0 (/mnt/d/dev_learn/learnrustbyai_fk/rust_course/02_intro/2.12_包和模块/code_visibility)\nerror[E0603]: module `hosting` is private\n --> src/lib.rs:9:21\n  |\n9 |     front_of_house::hosting::add_to_waitlist();\n  |                     ^^^^^^^  --------------- function `add_to_waitlist` is not publicly re-exported\n  |                     |\n  |                     private module\n  |\nnote: the module `hosting` is defined here\n --> src/lib.rs:2:5\n  |\n2 |     mod hosting {\n  |     ^^^^^^^^^^^\n\nFor more information about this error, try `rustc --explain E0603`.\nerror: could not compile `code_visibility` (lib) due to 1 previous error\n"
     ]
    }
   ],
   "source": [
    "! cd code_visibility && cargo build"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "错误信息很清晰：`hosting` 模块是私有的，无法在包根进行访问，那么为何 `front_of_house` 模块就可以访问？因为它和 `eat_at_restaurant` 同属于一个包根作用域内，同一个模块内的代码自然不存在私有化问题（所以我们之前章节的代码都没有报过这个错误！）。\n",
    "\n",
    "模块不仅仅对于组织代码很有用，它还能定义代码的私有化边界：在这个边界内，什么内容能让外界看到，什么内容不能，都有很明确的定义。因此，如果希望让函数或者结构体等类型变成私有化的，可以使用模块。\n",
    "\n",
    "Rust 出于安全的考虑，默认情况下，所有的类型都是私有化的，包括函数、方法、结构体、枚举、常量，是的，就连模块本身也是私有化的。在中国，父亲往往不希望孩子拥有小秘密，但是在 Rust 中，**父模块完全无法访问子模块中的私有项，但是子模块却可以访问父模块、父父..模块的私有项**。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### pub 关键字"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "类似其它语言的 `public` 或者 Go 语言中的首字母大写，Rust 提供了 `pub` 关键字，通过它你可以控制模块和模块中指定项的可见性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "function `add_to_waitlist` is private",
     "output_type": "error",
     "traceback": [
      "    crate::front_of_house::hosting::add_to_waitlist();",
      "\u001b[91m                                    ^^^^^^^^^^^^^^^\u001b[0m \u001b[94mprivate function\u001b[0m",
      "function `add_to_waitlist` is private"
     ]
    }
   ],
   "source": [
    "mod front_of_house {\n",
    "    pub mod hosting {\n",
    "        fn add_to_waitlist() {}\n",
    "    }\n",
    "}\n",
    "\n",
    "pub fn eat_at_restaurant() {\n",
    "    // 绝对路径\n",
    "    crate::front_of_house::hosting::add_to_waitlist();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "哦？难道模块可见还不够，还需要将函数 `add_to_waitlist` 标记为可见的吗？ 是的，没错，模块可见性不代表模块内部项的可见性，模块的可见性仅仅是允许其它模块去引用它，但是想要引用它内部的项，还得继续将对应的项标记为 `pub`。\n",
    "\n",
    "在实际项目中，一个模块需要对外暴露的数据和 API 往往就寥寥数个，如果将模块标记为可见代表着内部项也全部对外可见，那你是不是还得把那些不可见的，一个一个标记为 `private`？反而是更麻烦的多。\n",
    "\n",
    "既然知道了如何解决，那么我们为函数也标记上 `pub`："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "mod front_of_house {\n",
    "    pub mod hosting {\n",
    "        pub fn add_to_waitlist() {}\n",
    "    }\n",
    "}\n",
    "\n",
    "pub fn eat_at_restaurant() {\n",
    "    // 绝对路径\n",
    "    crate::front_of_house::hosting::add_to_waitlist();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用 super 引用模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在[用路径引用模块](https://course.rs/basic/crate-module/module.html#用路径引用模块)中，我们提到了相对路径有三种方式开始：`self`、`super`和 `crate` 或者模块名，其中第三种在前面已经讲到过，现在来看看通过 `super` 的方式引用模块项。\n",
    "\n",
    "`super` 代表的是父模块为开始的引用方式，非常类似于文件系统中的 `..` 语法：`../a/b` 文件名：src/lib.rs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "fn serve_order() {}\n",
    "\n",
    "// 厨房模块\n",
    "mod back_of_house {\n",
    "    fn fix_incorrect_order() {\n",
    "        cook_order();\n",
    "        super::serve_order();\n",
    "    }\n",
    "\n",
    "    fn cook_order() {}\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用 self 引用模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`self` 其实就是引用自身模块中的项，也就是说和我们之前章节的代码类似，都调用同一模块中的内容，区别在于之前章节中直接通过名称调用即可，而 `self`，你得多此一举："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "fn serve_order() {\n",
    "    self::back_of_house::cook_order() // 是的，多此一举，因为完全可以直接调用 `back_of_house`，但是 `self` 还有一个大用处，在下一节中我们会讲。\n",
    "}\n",
    "\n",
    "mod back_of_house {\n",
    "    fn fix_incorrect_order() {\n",
    "        cook_order();\n",
    "        crate::serve_order();\n",
    "    }\n",
    "\n",
    "    pub fn cook_order() {}\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 结构体和枚举的可见性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "为何要把结构体和枚举的可见性单独拎出来讲呢？因为这两个家伙的成员字段拥有完全不同的可见性：\n",
    "\n",
    "- 将结构体设置为 `pub`，但它的所有字段依然是私有的\n",
    "- 将枚举设置为 `pub`，它的所有字段也将对外可见\n",
    "\n",
    "原因在于，枚举和结构体的使用方式不一样。如果枚举的成员对外不可见，那该枚举将一点用都没有，因此枚举成员的可见性自动跟枚举可见性保持一致，这样可以简化用户的使用。\n",
    "\n",
    "而结构体的应用场景比较复杂，其中的字段也往往部分在 A 处被使用，部分在 B 处被使用，因此无法确定成员的可见性，那索性就设置为全部不可见，将选择权交给程序员。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 模块与文件分离"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在之前的例子中，我们所有的模块都定义在 `src/lib.rs` 中，但是当模块变多或者变大时，需要将模块放入一个单独的文件中，让代码更好维护。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "现在，把 `front_of_house` 前厅分离出来，放入一个单独的文件中 [`src/front_of_house.rs`](./front_of_house/src/front_of_house.rs)\n",
    "\n",
    "然后，将以下代码留在 [`src/lib.rs`](./front_of_house/src/lib.rs) 中："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "需要注意的是，和之前代码中 `mod front_of_house{..}` 的完整模块不同，现在的代码中，模块的声明和实现是分离的，实现是在单独的 `front_of_house.rs` 文件中，然后通过 `mod front_of_house;` 这条声明语句从该文件中把模块内容加载进来。因此我们可以认为，模块 `front_of_house` 的定义还是在 `src/lib.rs` 中，只不过模块的具体内容被移动到了 `src/front_of_house.rs` 文件中。\n",
    "\n",
    "在这里出现了一个新的关键字 `use`，联想到其它章节我们见过的标准库引入 `use std::fmt;`，可以大致猜测，该关键字用来将外部模块中的项引入到当前作用域中来，这样无需冗长的父模块前缀即可调用：`hosting::add_to_waitlist();`，在下节中，我们将对 `use` 进行详细的讲解。\n",
    "\n",
    "当一个模块有许多子模块时，我们也可以通过文件夹的方式来组织这些子模块。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在上述例子中，我们可以创建一个目录 `front_of_house`，然后在文件夹里创建一个 [`hosting.rs`](./front_of_house/src/front_of_house/hosting.rs) 文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       ".\n",
       "├── Cargo.lock\n",
       "├── Cargo.toml\n",
       "└── src\n",
       "    ├── front_of_house\n",
       "    │   └── hosting.rs\n",
       "    └── lib.rs\n",
       "\n",
       "2 directories, 4 files\n"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd front_of_house && tree"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "Shell command failed with exit code 101:    Compiling front_of_house v0.1.0 (/mnt/d/dev_learn/learnrustbyai_fk/rust_course/02_intro/2.12_包和模块/front_of_house)\nerror[E0583]: file not found for module `front_of_house`\n --> src/lib.rs:1:1\n  |\n1 | mod front_of_house; // 告诉 Rust 从另一个和模块 `front_of_house` 同名的文件中加载该模块的内容\n  | ^^^^^^^^^^^^^^^^^^^\n  |\n  = help: to create the module `front_of_house`, create file \"src/front_of_house.rs\" or \"src/front_of_house/mod.rs\"\n  = note: if there is a `mod front_of_house` elsewhere in the crate already, import it with `use crate::...` instead\n\nFor more information about this error, try `rustc --explain E0583`.\nerror: could not compile `front_of_house` (lib) due to 1 previous error\n",
     "output_type": "error",
     "traceback": [
      "Shell command failed with exit code 101:    Compiling front_of_house v0.1.0 (/mnt/d/dev_learn/learnrustbyai_fk/rust_course/02_intro/2.12_包和模块/front_of_house)\nerror[E0583]: file not found for module `front_of_house`\n --> src/lib.rs:1:1\n  |\n1 | mod front_of_house; // 告诉 Rust 从另一个和模块 `front_of_house` 同名的文件中加载该模块的内容\n  | ^^^^^^^^^^^^^^^^^^^\n  |\n  = help: to create the module `front_of_house`, create file \"src/front_of_house.rs\" or \"src/front_of_house/mod.rs\"\n  = note: if there is a `mod front_of_house` elsewhere in the crate already, import it with `use crate::...` instead\n\nFor more information about this error, try `rustc --explain E0583`.\nerror: could not compile `front_of_house` (lib) due to 1 previous error\n"
     ]
    }
   ],
   "source": [
    "! cd front_of_house && cargo build"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "是的，如果需要将文件夹作为一个模块，我们需要进行显示指定暴露哪些子模块\n",
    "\n",
    "在 `front_of_house` **同级**目录里创建一个与模块（目录）**同名**的 rs 文件 [`front_of_house.rs`](./front_of_house/src/front_of_house.rs)，在新版本里，更建议使用这样的命名方式来避免项目中存在大量同名的 `mod.rs` 文件"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       ".\n",
       "├── Cargo.lock\n",
       "├── Cargo.toml\n",
       "└── src\n",
       "    ├── front_of_house\n",
       "    │   └── hosting.rs\n",
       "    ├── front_of_house.rs\n",
       "    └── lib.rs\n",
       "\n",
       "2 directories, 5 files\n"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "! cd front_of_house && tree"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 使用 use 引入模块及受限可见性\n",
    "\n",
    "- https://course.rs/basic/crate-module/use.html\n",
    "- https://practice-zh.course.rs/crate-module/use-pub.html\n",
    "- https://github.com/sunface/rust-by-practice/blob/master/solutions/crate-module/use-pub.md"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 Rust 中，可以使用 `use` 关键字把路径提前引入到当前作用域中，随后的调用就可以省略该路径，极大地简化了代码。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 基本引入方式"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在 Rust 中，可以通过 **绝对路径** 或 **相对路径** 使用 `use` 关键字引入模块或其中的项。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **绝对路径引入**：从 `crate` 根开始，例如 `use crate::front_of_house::hosting;`，调用时写 `hosting::add_to_waitlist()`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "mod front_of_house {\n",
    "    pub mod hosting {\n",
    "        pub fn add_to_waitlist() {}\n",
    "    }\n",
    "}\n",
    "\n",
    "use crate::front_of_house::hosting;\n",
    "\n",
    "pub fn eat_at_restaurant() {\n",
    "    hosting::add_to_waitlist();\n",
    "    hosting::add_to_waitlist();\n",
    "    hosting::add_to_waitlist();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **相对路径引入**：从当前模块出发，例如 `use front_of_house::hosting::add_to_waitlist;`，调用时可直接写 `add_to_waitlist()`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "mod front_of_house {\n",
    "    pub mod hosting {\n",
    "        pub fn add_to_waitlist() {}\n",
    "    }\n",
    "}\n",
    "\n",
    "use front_of_house::hosting::add_to_waitlist;\n",
    "\n",
    "pub fn eat_at_restaurant() {\n",
    "    add_to_waitlist();\n",
    "    add_to_waitlist();\n",
    "    add_to_waitlist();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "选择引入**模块**还是**具体函数/结构体**取决于场景：\n",
    "- 若要使用模块中多个项或避免命名冲突 → 引入模块；\n",
    "- 若只需单个项 → 直接引入该函数或结构体（如 `use std::collections::HashMap;`）。\n",
    "\n",
    "一般建议：**优先使用最细粒度的引入方式，除非造成混淆或冲突。**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 例如，如果想使用 HashMap，那么直接引入该结构体是比引入模块更好的选择，因为在 collections 模块中，我们只需要使用一个 HashMap 结构体：\n",
    "\n",
    "use std::collections::HashMap;\n",
    "\n",
    "fn main() {\n",
    "    let mut map = HashMap::new();\n",
    "    map.insert(1, 2);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 避免同名引用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 模块::函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 避免同名冲突的关键，就是使用父模块的方式来调用, `模块::Result`\n",
    "\n",
    "use std::fmt;\n",
    "use std::io;\n",
    "\n",
    "fn function1() -> fmt::Result { \n",
    "    // --snip--\n",
    "}\n",
    "\n",
    "fn function2() -> io::Result<()> {\n",
    "    // --snip--\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### as 别名引用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "use std::fmt::Result;\n",
    "use std::io::Result as IoResult; // 使用 as 关键字来解决，它可以赋予引入项一个全新的名称\n",
    "\n",
    "fn function1() -> Result {\n",
    "    // --snip--\n",
    "}\n",
    "\n",
    "fn function2() -> IoResult<()> {\n",
    "    // --snip--\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 引入项再导出"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当外部的模块项 `A` 被引入到当前模块中时，它的可见性自动被设置为私有的，如果你希望允许其它外部代码引用我们的模块项 `A`，那么可以对它进行再导出："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "mod front_of_house {\n",
    "    pub mod hosting {\n",
    "        pub fn add_to_waitlist() {}\n",
    "    }\n",
    "}\n",
    "\n",
    "pub use crate::front_of_house::hosting; // 这里 `use` 代表引入 `hosting` 模块到当前作用域，`pub` 表示将该引入的内容再度设置为可见\n",
    "\n",
    "pub fn eat_at_restaurant() {\n",
    "    hosting::add_to_waitlist();\n",
    "    hosting::add_to_waitlist();\n",
    "    hosting::add_to_waitlist();\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当你希望将内部的实现细节隐藏起来或者按照某个目的组织代码时，可以使用 `pub use` 再导出，例如统一使用一个模块来提供对外的 API，那该模块就可以引入其它模块中的 API，然后进行再导出，最终对于用户来说，所有的 API 都是由一个模块统一提供的。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用第三方包"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "之前我们一直在引入标准库模块或者自定义模块，现在来引入下第三方包中的模块，关于如何引入外部依赖，我们在 [Cargo 入门](https://course.rs/first-try/cargo.html#package-配置段落)中就有讲，这里直接给出操作步骤：\n",
    "\n",
    "1. 修改 `Cargo.toml` 文件，在 `[dependencies]` 区域添加一行：`rand = \"0.8.3\"`\n",
    "2. 此时，如果你用的是 `VSCode` 和 `rust-analyzer` 插件，该插件会自动拉取该库，你可能需要等它完成后，再进行下一步（VSCode 左下角有提示）\n",
    "\n",
    "好了，此时，`rand` 包已经被我们添加到依赖中，下一步就是在代码中使用："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "use rand::Rng;\n",
    "\n",
    "fn main() {\n",
    "    let secret_number = rand::thread_rng().gen_range(1..101);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "这里使用 `use` 引入了第三方包 `rand` 中的 `Rng` 特征，因为我们需要调用的 `gen_range` 方法定义在该特征中。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [crates.io，lib.rs](https://course.rs/basic/crate-module/use.html#cratesiolibrs)\n",
    "\n",
    "Rust 社区已经为我们贡献了大量高质量的第三方包，你可以在 `crates.io` 或者 `lib.rs` 中检索和使用，从目前来说查找包更推荐 `lib.rs`，搜索功能更强大，内容展示也更加合理，但是下载依赖包还是得用`crates.io`。\n",
    "\n",
    "你可以在网站上搜索 `rand` 包，看看它的文档使用方式是否和我们之前引入方式相一致：在网上找到想要的包，然后将你想要的包和版本信息写入到 `Cargo.toml` 中。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用 {} 简化引入方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "use std::collections::HashMap;\n",
    "use std::collections::BTreeMap;\n",
    "use std::collections::HashSet;\n",
    "\n",
    "use std::cmp::Ordering;\n",
    "use std::io;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 简化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "use std::collections::{HashMap,BTreeMap,HashSet};\n",
    "use std::{cmp::Ordering, io};"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "use std::io;\n",
    "use std::io::Write;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 简化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "use std::io::{self, Write};"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### [self](https://course.rs/basic/crate-module/use.html#self)\n",
    "\n",
    "上面使用到了模块章节提到的 `self` 关键字，用来替代模块自身，结合上一节中的 `self`，可以得出它在模块中的两个用途：\n",
    "\n",
    "- `use self::xxx`，表示加载当前模块中的 `xxx`。此时 `self` 可省略\n",
    "- `use xxx::{self, yyy}`，表示，加载当前路径下模块 `xxx` 本身，以及模块 `xxx` 下的 `yyy`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用 * 引入模块下的所有项"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "use std::collections::*;"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "当使用 `*` 来引入的时候要格外小心，因为你很难知道到底哪些被引入到了当前作用域中，有哪些会和你自己程序中的名称相冲突："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "use std::collections::*;\n",
    "\n",
    "struct HashMap;\n",
    "fn main() {\n",
    "   let mut v =  HashMap::new();\n",
    "   v.insert(\"a\", 1);\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在实际项目中，这种引用方式往往用于快速写测试代码，它可以把所有东西一次性引入到 `tests` 模块中。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 受限的可见性"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> **tl;dr：**\n",
    "\n",
    "Rust 的可见性不仅能控制“是否公开”，还能控制“公开到哪里”。\n",
    "\n",
    "- `pub(crate)`：仅在当前包内可见。\n",
    "- `pub(in path)`：只在指定模块（如 `crate::a`）内可见。\n",
    "- 父模块的内容对子模块可见，但子模块的内容默认对父模块不可见。\n",
    "- 若只想让某些内部模块访问特定项，可用 `pub(in ...)` 精确限定可见范围，实现“受限可见性”。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 可见性修饰符     | 含义                   |\n",
    "| ---------------- | ---------------------- |\n",
    "| `pub`            | 对所有模块公开         |\n",
    "| `pub(crate)`     | 仅在当前包内可见       |\n",
    "| `pub(super)`     | 对父模块可见           |\n",
    "| `pub(in path)`   | 仅在指定模块路径内可见 |\n",
    "| *(默认省略 pub)* | 仅在当前模块内可见     |\n",
    "\n",
    "<br/>\n",
    "\n",
    "<img src=\"./images/2.12.1.png\" alt=\"2.12.1\" style=\"zoom:50%;\" />"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [],
   "source": [
    "// 文件：src/lib.rs\n",
    "\n",
    "// 模块 a 对外公开\n",
    "pub mod a {\n",
    "    // 公共常量：任何地方都能访问\n",
    "    pub const I: i32 = 3;\n",
    "\n",
    "    // 私有函数：只有当前模块 a 内可访问\n",
    "    fn semisecret(x: i32) -> i32 {\n",
    "        // 引用子模块中的常量 J（仅在 a 内可见）\n",
    "        use self::b::c::J;\n",
    "        x + J\n",
    "    }\n",
    "\n",
    "    // 公共函数：对外可见\n",
    "    pub fn bar(z: i32) -> i32 {\n",
    "        semisecret(I) * z\n",
    "    }\n",
    "\n",
    "    pub fn foo(y: i32) -> i32 {\n",
    "        semisecret(I) + y\n",
    "    }\n",
    "\n",
    "    // 模块 b 只在 a 内可见\n",
    "    mod b {\n",
    "        // 模块 c 只对 crate::a 可见\n",
    "        pub(in crate::a) mod c {\n",
    "            // 常量 J 只对 crate::a 可见\n",
    "            pub(in crate::a) const J: i32 = 4;\n",
    "        }\n",
    "    }\n",
    "}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "bar = 14\n",
      "foo = 12\n",
      "I = 3\n"
     ]
    }
   ],
   "source": [
    "// 可以访问公共函数和常量\n",
    "\n",
    "println!(\"bar = {}\", a::bar(2));\n",
    "println!(\"foo = {}\", a::foo(5));\n",
    "println!(\"I = {}\", a::I);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "module `b` is private",
     "output_type": "error",
     "traceback": [
      "println!(\"{}\", a::b::c::J); // J 仅对 a 可见",
      "\u001b[91m                  ^\u001b[0m \u001b[94mprivate module\u001b[0m",
      "println!(\"{}\", a::b::c::J); // J 仅对 a 可见",
      "\u001b[91m                        ^\u001b[0m \u001b[94mconstant `J` is not publicly re-exported\u001b[0m",
      "module `b` is private"
     ]
    }
   ],
   "source": [
    "println!(\"{}\", a::b::c::J); // J 仅对 a 可见"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "vscode": {
     "languageId": "rust"
    }
   },
   "outputs": [
    {
     "ename": "Error",
     "evalue": "function `semisecret` is private",
     "output_type": "error",
     "traceback": [
      "println!(\"{}\", a::semisecret(1)); // 私有函数",
      "\u001b[91m                  ^^^^^^^^^^\u001b[0m \u001b[94mprivate function\u001b[0m",
      "function `semisecret` is private"
     ]
    }
   ],
   "source": [
    "println!(\"{}\", a::semisecret(1)); // 私有函数"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Rust",
   "language": "rust",
   "name": "rust"
  },
  "language_info": {
   "codemirror_mode": "rust",
   "file_extension": ".rs",
   "mimetype": "text/rust",
   "name": "Rust",
   "pygment_lexer": "rust",
   "version": ""
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
